<script setup lang="ts">
import {
  ArrowLeftBold,
  ArrowRightBold,
} from '@element-plus/icons-vue'
import { useCurrentElement } from '@vueuse/core'
import elementResizeDetectorMaker from 'element-resize-detector'
import { debounce } from 'lodash-es'
import type { Ref } from 'vue'
import type { StatisticsDataItem } from '../type.d'
import StatisticsCard from '../StatisticsCard/index.vue'
import { handleIdentity, identity } from '../'
import type { StatisticsCarouselProps } from './type'

defineOptions({ name: 'StatisticsCarousel' })
const props = defineProps<StatisticsCarouselProps>()
const emits = defineEmits<{
  click: [data: StatisticsDataItem, e: Event]
}>()

const active = inject<Ref<string>>(identity, ref(''))
const _handleClick = inject(
  handleIdentity,
  (..._: any[]) => {},
)
const resizeObserver = elementResizeDetectorMaker()
const container = useCurrentElement()
const [isNext, setIsNext] = useState(false)
const [isPrevious, setIsPrevious] = useState(false)
const [innerWidth, setInnerWidth] = useNativeState(0)
const [showCount, setShowCount] = useState(0)

/** 项宽度 */
const EL_WIDTH = 300
/** 按钮宽度 */
const BTN_WIDTH = 30
/** 间隙 */
const GAP = 20
/** 动画id */
let aniGlobal: number | null = 0

const innerRef = ref<HTMLElement | null>()

onMounted(() => {
  bindEvent()
})

watch(
  () => props.data,
  () => {
    handleResize()
  },
)

function bindEvent() {
  resizeObserver.listenTo(
    container.value,
    debounce(handleResize, 300),
  )
  // 初始化
  handleResize()
}
// 处理宽度变化
function handleResize() {
  const containerWidth = (container.value as HTMLElement)?.clientWidth
  const l = props.data.length
  const _innerWidth = l * EL_WIDTH + (l - 1) * GAP
  const scrollLeft = innerRef.value?.scrollLeft ?? 0

  let count = 0
  setInnerWidth(_innerWidth)
  if (_innerWidth > containerWidth) {
    count = Math.floor(containerWidth / (EL_WIDTH + GAP))
    if (scrollLeft < _innerWidth - containerWidth) {
      setIsNext(true)
    }
  }
  else {
    setIsNext(false)
    setIsPrevious(false)
  }
  setShowCount(count)
}
function handleNext() {
  const scrollLeft = innerRef.value?.scrollLeft ?? 0
  /** 位移 */
  let dw = scrollLeft + (EL_WIDTH + GAP) * showCount.value

  /** 剩余宽度 */
  const surplusWidth
    = innerWidth.value
    - scrollLeft
    - (innerRef.value?.offsetWidth ?? 0)
  // !判断剩余宽度是否小于需要切换的宽度
  if (
    surplusWidth
    < (EL_WIDTH + GAP) * showCount.value - GAP
  ) {
    dw = scrollLeft + surplusWidth
    setIsNext(false)
  }
  // innerRef.value?.scrollTo?.(dw, 0);
  aniChange(dw)
  setIsPrevious(true)
}
function handlePrev() {
  const scrollLeft = innerRef.value?.scrollLeft ?? 0

  /** 位移 */
  let dw = scrollLeft - (EL_WIDTH + GAP) * showCount.value
  const i = Math.ceil(dw / (EL_WIDTH + GAP))
  dw = i * (EL_WIDTH + GAP)
  if (dw <= 0) {
    setIsPrevious(false)
    setIsNext(true)
  }
  else if (
    dw
    < innerWidth.value - (innerRef.value?.offsetWidth ?? 0)
  ) {
    setIsNext(true)
  }
  // innerRef.value?.scrollTo?.(dw, 0);
  aniChange(dw)
}
/** 动画滚动 */
function aniChange(target: number) {
  clearAni()
  const step = 10
  const scrollLeft = innerRef.value?.scrollLeft ?? 0
  let i = scrollLeft
  // console.log('scrollLeft', scrollLeft);
  // console.log('target', target);

  const _change = (() => {
    if (scrollLeft > target) {
      return () => {
        i -= step
      }
    }
    else {
      return () => {
        i += step
      }
    }
  })()
  const isOk = (() => {
    if (scrollLeft > target) {
      return () => i <= target
    }
    else {
      return () => i >= target
    }
  })()
  const handle = () => {
    aniGlobal = requestAnimationFrame(() => {
      _change()
      innerRef.value?.scrollTo?.(i, 0)
      if (isOk()) {
        clearAni()
      }
      else {
        handle()
      }
    })
  }
  handle()
}
function clearAni() {
  aniGlobal && cancelAnimationFrame(aniGlobal)
}
function handleClick(data: StatisticsDataItem, e: Event) {
  active.value = data.type
  emits('click', data, e)
  _handleClick?.(data, e)
}
</script>

<template>
  <div
    class="overflow statistics-carousel relative flex gap-col-xs align-start"
  >
    <Transition
      enter-active-class="animate__animated animate__faster animate__fadeInLeft"
      leave-active-class="animate__animated animate__faster animate__fadeOutLeft"
    >
      <button
        v-show="isPrevious"
        class="flex-incompressible statistics-carousel-btn previous"
        @click="handlePrev"
      >
        <el-icon><ArrowLeftBold /></el-icon>
      </button>
    </Transition>
    <div
      ref="innerRef"
      class="flex-fillRemaining padding-bottom-sm overflow statistics-carousel-container"
    >
      <div
        class="align-center statistics-carousel-inner flex"
      >
        <StatisticsCard
          v-for="item in data"
          :key="item.type"
          v-bind="item"
          class="flex-incompressible"
          :class="[
            {
              active: active === item.type,
            },
          ]"
          @click="handleClick(item, $event)"
        />
      </div>
    </div>
    <Transition
      enter-active-class="animate__animated animate__faster animate__fadeInRight"
      leave-active-class="animate__animated animate__faster animate__fadeOutRight"
    >
      <button
        v-show="isNext"
        class="statistics-carousel-btn flex-incompressible next"
        @click="handleNext"
      >
        <el-icon><ArrowRightBold /></el-icon>
      </button>
    </Transition>
  </div>
</template>

<style lang="scss" scoped>
//------------------组件样式------------------
.statistics-carousel {
  --statistics-carousel-height: var(
    --statistics-tabs-height,
    130px
  );
  &-btn {
    cursor: pointer;
    width: calc(1px * v-bind(BTN_WIDTH));
    height: var(--statistics-carousel-height);
    border: none;
    outline: none;
    background: var(--el-border-color-lighter);
  }
  &-inner {
    column-gap: calc(1px * v-bind(GAP));
  }
}
//-------------样式穿透-------------
</style>
